﻿
@using Gurux.DLMS.AMI.Shared.DIs

@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using Gurux.DLMS.AMI.Shared.DTOs
@using Gurux.DLMS.AMI.Shared.Rest
@using Microsoft.AspNetCore.SignalR.Client
@using Gurux.DLMS.AMI.Shared
@using Gurux.DLMS.AMI.Shared.Enums
@using Gurux.DLMS.AMI.Module;
    using Gurux.DLMS.AMI.Shared.DTOs.Module

@attribute [Authorize(Roles = GXRoles.Admin)]
@inject NavigationManager NavigationManager
@inject HttpClient Http
@inject IGXNotifier Notifier
@inject GXModuleService modules
@implements IDisposable

<h1>@Properties.Resources.ModulesTitle</h1>
<AuthorizeView Roles=@GXRoles.ToString(GXRoles.Admin, GXRoles.ModuleManager)>
    <MenuControl RightCorner="true">
        <ChildContent>
            <MenuItem Text="@Properties.Resources.Add" Icon="oi oi-plus" OnClick="@OnAdd" />
        </ChildContent>
    </MenuControl>
</AuthorizeView>

<GXTable @ref="table"
         Context="module"
         ItemsProvider="@GetItems"
         SelectionMode="SelectionMode.Single"
         ShowRemoved="false"
         ShowAllUsers="false"
         OnSearch="@Updated">
    <FilterContent>
        <th>
            <input class="form-control" type="text" placeholder="@Properties.Resources.FilterByName"
                   @onchange="@((ChangeEventArgs __e) => filter.Id = Convert.ToString(__e.Value))" />
        </th>
        <th>
            <input class="form-control" type="text" placeholder="Filter by version..."
                   @onchange="@((ChangeEventArgs __e) => filter.Version = Convert.ToString(__e.Value))" />
        </th>
        <th>
            <input class="form-control" type="text" placeholder="Filter by latest version..."
                   @onchange="@((ChangeEventArgs __e) => filter.AvailableVersion = Convert.ToString(__e.Value))" />
        </th>
        <th>
            <input class="form-control" placeholder="按创建时间..."
                   type="datetime-local"
                   @onchange="@((ChangeEventArgs __e) => filter.CreationTime = Convert.ToDateTime(__e.Value))" />
        </th>
        <th>
            <input class="form-control" placeholder="Filter by updated time..."
                   type="datetime-local"
                   @onchange="@((ChangeEventArgs __e) => filter.Updated = Convert.ToDateTime(__e.Value))" />
        </th>
    </FilterContent>
    <MenuContent>
        <AuthorizeView Roles=@GXRoles.ToString(GXRoles.Admin, GXRoles.AgentGroupManager)>
            <ContextMenuItem Text="@Properties.Resources.Install"
                             Icon="oi oi-plus"
                             OnClick="@OnInstall"></ContextMenuItem>
        </AuthorizeView>
    </MenuContent>
    <HeaderContent>
        <th>@Properties.Resources.Name</th>
        <th>@Properties.Resources.Version</th>
        <th>@Properties.Resources.AvailableVersion</th>
        <th>@Properties.Resources.CreationTime</th>
        <th>@Properties.Resources.Updated</th>
    </HeaderContent>
    <ItemContent>
        <td><span class="@module.Icon" aria-hidden="true"></span>@module.Id</td>
        <td>@module.Version</td>
        <td>@module.AvailableVersion</td>
        <td>@module.CreationTime</td>
        <td>@module.Updated</td>
    </ItemContent>
</GXTable>
<br />
<Confirm @ref="RestartConfirmation"
         ConfirmationChanged="OnRestartConfirmation"
         OkTitle="@Properties.Resources.Restart"
         ConfirmationTitle="Confirm restart"
         AllowDelete="false"
         ConfirmationMessage="@Properties.Resources.ModuleNeedsRestart">
</Confirm>

@code {
    /// <summary>
    /// System error filter.
    /// </summary>
    private GXModule filter = new GXModule();

    /// <summary>
    /// User is asked should server restart.
    /// </summary>
    protected ConfirmBase? RestartConfirmation;


    /// <summary>
    /// Table reference.
    /// </summary>
    protected GXTable<GXModule>? table;

    /// <summary>
    /// Update table.
    /// </summary>
    protected async Task Updated()
    {
        try
        {
            if (table != null)
            {
                Notifier?.ClearStatus();
                await table.RefreshDataAsync(true);
            }
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
    }

    protected override void OnInitialized()
    {
        try
        {
            Notifier.ProgressStart();
            Notifier.ClearStatus();
            Notifier.On<IEnumerable<GXModule>>(this, nameof(IGXHubEvents.ModuleUpdate), async (modules) =>
            {
                await Updated();
            });
            Notifier.Clear();
            Notifier.UpdateButtons();
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
        finally
        {
            Notifier?.ProgressEnd();
        }
    }

    private async ValueTask<ItemsProviderResult<GXModule>> GetItems(GXItemsProviderRequest request)
    {
        //Don't clear status or error is lost.
        Notifier?.ProgressStart();
        try
        {
            ListModules req = new ListModules()
                {
                    Index = request.StartIndex,
                    Count = request.Count,
                    Filter = filter,
                    OrderBy = request.OrderBy,
                    Descending = request.Descending,
                    AllUsers = request.ShowAllUserData
                };
            var ret = await Http.PostAsJson<ListModulesResponse>("api/Module/List", req, request.CancellationToken);
            //Get only selected amount of the modules.
            return new ItemsProviderResult<GXModule>(ret.Modules, ret.Count);
        }
        catch (TaskCanceledException)
        {
            //Let the table component handle this.
            throw;
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
        finally
        {
            Notifier?.ProgressEnd();
        }
        return default;
    }

    /// <summary>
    /// Install new module.
    /// </summary>
    public async void OnInstall()
    {
        try
        {
            Notifier.ProgressStart();
            Notifier.ClearStatus();
            if (table?.Active == null)
            {
                throw new Exception(Properties.Resources.InvalidTarget);
            }
            @if ((table.Active.Status & AMI.Shared.DTOs.Enums.ModuleStatus.Installed) != 0)
            {
                throw new Exception(string.Format("Module {0} is already installed.", table.Active.Id));
            }
            UpdateModule req = new UpdateModule() { Module = table.Active };
            var ret = await Http.PostAsJson<UpdateModuleResponse>("api/Module/Install", req);
            if (RestartConfirmation != null && ret.Restart)
            {
                RestartConfirmation.Show();
            }
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
        finally
        {
            Notifier?.ProgressEnd();
        }
    }

    /// <summary>
    /// Add new module.
    /// </summary>
    public void OnAdd()
    {
        try
        {
            Notifier.ClearStatus();
            ClientHelpers.NavigateTo(NavigationManager, Notifier, "/config/Module/Add");
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
    }

    /// <summary>
    /// Ask should the application restart.
    /// </summary>
    public async Task OnRestartConfirmation(ConfirmArgs args)
    {
        try
        {
            if (args.Confirm)
            {
                StopApplicationRequest req = new StopApplicationRequest();
                await Http.PostAsJson("api/Configuration/Restart", req);
            }
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
    }

    void OnClose(object sender)
    {
        ClientHelpers.NavigateTo(NavigationManager, Notifier, "/module");
    }

    public void Dispose()
    {
        Notifier.RemoveListener(this);
    }
}
